import axios, { AxiosInstance } from 'axios';
import { Transaction, ChainType } from '../../types';
import { createModuleLogger } from '../../utils/logger';
import { PriceService } from '../price/PriceService';
import { AddressLabelService } from '../address/AddressLabelService';
import { ConfigService } from '../config/ConfigService';
import config from '../../config';
import { ChainMonitorConfig } from '../config/ChainMonitorConfigService';

const logger = createModuleLogger('solana-monitor');

interface SolanaBlock {
  blockHeight: number;
  blockTime: number;
  transactions: SolanaTransaction[];
}

interface SolanaTransaction {
  transaction: {
    signatures: string[];
    message: {
      accountKeys: string[];
      instructions: any[];
    };
  };
  meta: {
    fee: number;
    preBalances: number[];
    postBalances: number[];
    preTokenBalances?: any[];
    postTokenBalances?: any[];
    err: any;
  };
}

export class SolanaMonitor {
  private httpClient: AxiosInstance;
  private isRunning = false;
  private lastProcessedSlot = 0;
  private lastSuccessfulSlot = 0;
  private onTransactionCallback?: (transaction: Transaction) => void;
  private requestQueue: Array<() => Promise<any>> = [];
  private isProcessingQueue = false;
  private requestDelay = 200; // 200ms between requests for Solana
  private priceService: PriceService;
  private addressLabelService?: AddressLabelService;
  private configService: ConfigService | null = null;
  private consecutiveErrors = 0;
  private maxConsecutiveErrors = 5;
  private backfillInProgress = false;
  private chainConfig: ChainMonitorConfig | null = null;

  constructor() {
    this.priceService = PriceService.getInstance();
    
    // 创建HTTP客户端
    this.httpClient = axios.create({
      baseURL: config.chains.solana.rpcUrl,
      timeout: 30000,
      validateStatus: () => true,
      headers: {
        'Content-Type': 'application/json'
      }
    });
  }

  // 请求队列处理
  private async queueRequest<T>(requestFn: () => Promise<T>): Promise<T | null> {
    return new Promise((resolve) => {
      this.requestQueue.push(async () => {
        try {
          const result = await requestFn();
          resolve(result);
        } catch (error) {
          resolve(null);
        }
      });

      if (!this.isProcessingQueue) {
        this.processQueue();
      }
    });
  }

  private async processQueue(): Promise<void> {
    if (this.isProcessingQueue) return;
    this.isProcessingQueue = true;

    while (this.requestQueue.length > 0) {
      const request = this.requestQueue.shift();
      if (request) {
        await request();
        await new Promise(resolve => setTimeout(resolve, this.requestDelay));
      }
    }

    this.isProcessingQueue = false;
  }

  // Solana RPC调用
  private async solanaRpcCall(method: string, params: any[] = []): Promise<any> {
    const response = await this.httpClient.post('', {
      jsonrpc: '2.0',
      id: Date.now(),
      method,
      params
    });

    if (response.status !== 200) {
      throw new Error(`RPC call failed: ${response.status}`);
    }

    if (response.data.error) {
      throw new Error(`RPC error: ${response.data.error.message}`);
    }

    return response.data.result;
  }

  // 设置交易回调
  public setTransactionCallback(callback: (transaction: Transaction) => void): void {
    this.onTransactionCallback = callback;
  }

  // 设置地址标记服务
  public setAddressLabelService(service: AddressLabelService): void {
    this.addressLabelService = service;
  }

  // 设置配置服务
  public setConfigService(configService: ConfigService): void {
    this.configService = configService;
  }

  public setChainConfig(chainConfig: ChainMonitorConfig): void {
    this.chainConfig = chainConfig;
    logger.info(`🔧 SolanaMonitor 配置已更新: min=$${chainConfig.minValueUsd}, rpc=${chainConfig.rpcUrl}`);
    
    // 更新请求延迟
    this.requestDelay = chainConfig.requestDelay || 200;
    
    // 如果需要，更新RPC客户端
    if (chainConfig.rpcUrl !== config.chains.solana.rpcUrl) {
      this.httpClient = axios.create({
        baseURL: chainConfig.rpcUrl,
        timeout: 30000,
        validateStatus: () => true,
        headers: {
          'Content-Type': 'application/json'
        }
      });
      logger.info(`🔄 SolanaMonitor RPC已更新: ${chainConfig.rpcUrl}`);
    }
  }

  // 获取最小交易金额阈值
  private getMinTransactionValue(): number {
    if (this.chainConfig) {
      return this.chainConfig.minValueUsd;
    }

    if (this.configService) {
      const monitoringConfig = this.configService.getMonitoringConfig();
      return monitoringConfig.minTransactionValue;
    }
    return config.monitoring.defaultMinValue; // 回退到静态配置
  }

  // 开始监控
  public async start(): Promise<void> {
    if (this.isRunning) {
      logger.warn('⚠️ Solana监控已在运行中，跳过启动');
      return;
    }

    try {
      // 显示实际使用的RPC端点
      const actualRpcUrl = this.chainConfig?.rpcUrl || config.chains.solana.rpcUrl;
      logger.info(`🚀 正在初始化Solana监控器... RPC: ${actualRpcUrl}`);
      const testSlot = await this.getCurrentSlot();
      if (testSlot) {
        logger.info(`✅ Solana RPC连接成功，当前slot: ${testSlot}`);
      } else {
        throw new Error('无法获取Solana当前slot');
      }
      
      this.isRunning = true;
      
      // 获取当前slot
      const currentSlot = await this.getCurrentSlot();
      if (currentSlot) {
        this.lastProcessedSlot = currentSlot;
        logger.info(`📊 Solana监控器已连接，当前slot: ${this.lastProcessedSlot}，开始监控大额交易`);
        
        this.startPollingMonitoring(); // 非阻塞启动
      } else {
        throw new Error('无法获取Solana当前slot');
      }
    } catch (error) {
      logger.error('💥 启动Solana监控失败:', error);
      logger.error(`❌ Solana RPC连接失败: ${config.chains.solana.rpcUrl}`);
      this.isRunning = false;
      throw error;
    }
  }

  // 停止监控
  public async stop(): Promise<void> {
    logger.info('⏹️ 正在停止Solana监控器...');
    this.isRunning = false;
    // if (this.wsClient) { // This line was removed as per the new_code, as wsClient is no longer defined.
    //   this.wsClient.close();
    // }
    logger.info('✅ Solana监控器已完全停止');
  }

  // 获取当前slot
  private async getCurrentSlot(): Promise<number | null> {
    try {
      const result = await this.queueRequest(() => this.solanaRpcCall('getSlot'));
      return result;
    } catch (error) {
      logger.error('获取Solana当前slot失败:', error instanceof Error ? error.message : String(error));
      return null;
    }
  }

  // 轮询监控
  private async startPollingMonitoring(): Promise<void> {
    logger.info('Solana轮询监控模式已启动');
    
    while (this.isRunning) {
      try {
        const currentSlot = await this.getCurrentSlot();
        
        if (currentSlot && currentSlot > this.lastProcessedSlot) {
          logger.info(`🆕 Solana发现新slot: ${this.lastProcessedSlot + 1} 到 ${currentSlot}`);
          
          // 处理新的slot，但限制每次处理的数量以避免过载
          const maxSlotsPerBatch = 10;
          const endSlot = Math.min(currentSlot, this.lastProcessedSlot + maxSlotsPerBatch);
          
          for (let slot = this.lastProcessedSlot + 1; slot <= endSlot; slot++) {
            if (!this.isRunning) break;
            
            try {
              await this.processSlot(slot);
              this.lastProcessedSlot = slot;
            } catch (slotError) {
              logger.error(`处理Solana slot ${slot} 失败:`, slotError instanceof Error ? slotError.message : String(slotError));
              this.lastProcessedSlot = slot;
            }
          }
        } else {
          logger.info(`⏸️ Solana暂无新slot (当前: ${currentSlot}, 上次: ${this.lastProcessedSlot})`);
        }

        this.consecutiveErrors = 0;
        
      } catch (error) {
        this.consecutiveErrors++;
        
        if (this.consecutiveErrors <= this.maxConsecutiveErrors) {
          logger.warn(`Solana轮询监控出错 (${this.consecutiveErrors}/${this.maxConsecutiveErrors}):`, error);
          
          const backoffDelay = Math.min(1000 * Math.pow(2, this.consecutiveErrors - 1), 30000);
          logger.info(`Solana等待 ${backoffDelay/1000}秒 后重试...`);
          await new Promise(resolve => setTimeout(resolve, backoffDelay));
          
        } else {
          logger.error(`Solana连续错误过多，暂停监控 30秒:`, error instanceof Error ? error.message : String(error));
          await new Promise(resolve => setTimeout(resolve, 30000));
          this.consecutiveErrors = 0;
        }
      }

      if (this.isRunning && this.consecutiveErrors === 0) {
        await new Promise(resolve => setTimeout(resolve, config.monitoring.blockCheckInterval));
      }
    }
  }

  // 回溯补偿
  private async backfillMissedSlots(): Promise<void> {
    if (this.backfillInProgress || !this.isRunning) return;

    try {
      this.backfillInProgress = true;
      const currentSlot = await this.getCurrentSlot();
      
      if (!currentSlot || currentSlot <= this.lastSuccessfulSlot) {
        this.backfillInProgress = false;
        return;
      }

      const missedSlots = currentSlot - this.lastSuccessfulSlot;
      
      if (missedSlots > 1 && missedSlots <= 50) { // Solana回溯50个slot
        logger.warn(`🔄 Solana检测到 ${missedSlots} 个漏掉的slot，开始回溯补偿...`);
        
        for (let slot = this.lastSuccessfulSlot + 1; slot < currentSlot && slot < this.lastSuccessfulSlot + 50; slot++) {
          if (!this.isRunning) break;
          
          try {
            await this.processSlot(slot);
            this.lastSuccessfulSlot = slot;
            await new Promise(resolve => setTimeout(resolve, 500));
            
          } catch (error) {
            logger.debug(`回溯Solana slot ${slot} 失败，跳过`);
          }
        }
        
        logger.info(`✅ Solana slot回溯完成，已补偿到slot ${this.lastSuccessfulSlot}`);
      } else if (missedSlots > 50) {
        logger.warn(`⚠️ Solana漏掉slot过多 (${missedSlots})，跳过回溯，从当前slot继续`);
        this.lastSuccessfulSlot = currentSlot - 1;
      }

    } catch (error) {
      logger.error('Solana slot回溯失败:', error);
    } finally {
      this.backfillInProgress = false;
    }
  }

  // 处理slot
  private async processSlot(slot: number): Promise<void> {
    try {
      // 获取slot中的区块
      const block = await this.queueRequest(() => 
        this.solanaRpcCall('getBlock', [slot, {
          encoding: 'json',
          transactionDetails: 'full',
          rewards: false,
          maxSupportedTransactionVersion: 0
        }])
      );

      if (!block || !block.transactions) {
        logger.info(`❌ Solana slot ${slot} 数据无效，跳过. block存在: ${!!block}, transactions存在: ${!!block?.transactions}`);
        return;
      }

      // 每20个slot记录一次进度
      if (slot % 20 === 0) {
        logger.info(`📊 Solana监控进度: slot ${slot}, 交易数: ${block.transactions.length}`);
      }

      // 限制处理的交易数量
      const maxTransactions = Math.min(block.transactions.length, 30);
      

      
      
      
      for (let i = 0; i < maxTransactions; i++) {
        if (!this.isRunning) break;
        
        try {
          await this.processTransaction(block.transactions[i], slot, block.blockTime);
        } catch (error) {
          logger.error(`处理Solana交易 ${i} 失败:`, error);
        }
      }

    } catch (error) {
      logger.debug(`处理Solana slot ${slot} 失败:`, error);
    }
  }

  // 处理Solana交易
  private async processTransaction(tx: SolanaTransaction, slot: number, blockTime: number): Promise<void> {
    try {
      // 详细的验证日志

      
      if (!tx.meta || tx.meta.err || !tx.transaction || !tx.transaction.signatures || tx.transaction.signatures.length === 0) {
        return; // 跳过失败的交易
      }

      const signature = tx.transaction.signatures[0];
      if (!signature) return;
      
      // 首先检查SPL代币转账
      await this.processSPLTokenTransfers(tx, slot, blockTime);
      
      // 然后检查原生SOL转账
      await this.processNativeSOLTransfer(tx, slot, blockTime);

    } catch (error) {
      logger.debug(`处理Solana交易失败:`, error);
    }
  }

  // 处理SPL代币转账
  private async processSPLTokenTransfers(tx: SolanaTransaction, slot: number, blockTime: number): Promise<void> {
    try {
      const { preTokenBalances, postTokenBalances } = tx.meta;
      
      if (!preTokenBalances || !postTokenBalances) return;

      // 创建代币余额变化映射
      const tokenBalanceChanges = new Map<string, {
        mint: string;
        owner: string;
        change: number;
        decimals: number;
        fromOwner?: string;
        toOwner?: string;
      }>();

      // 分析代币余额变化
      for (const postBalance of postTokenBalances) {
        if (!postBalance.mint || !postBalance.owner || !postBalance.uiTokenAmount) continue;
        
        const mint = postBalance.mint;
        const owner = postBalance.owner;
        const postAmount = parseFloat(postBalance.uiTokenAmount.uiAmountString || '0');
        const decimals = postBalance.uiTokenAmount.decimals;
        
        // 查找对应的pre balance
        const preBalance = preTokenBalances.find(
          pre => pre.mint === mint && pre.owner === owner
        );
        const preAmount = preBalance?.uiTokenAmount?.uiAmountString ? 
          parseFloat(preBalance.uiTokenAmount.uiAmountString) : 0;
        
        const change = postAmount - preAmount;
        
        if (Math.abs(change) > 0) {
          const key = `${mint}_${owner}`;
          tokenBalanceChanges.set(key, {
            mint,
            owner,
            change,
            decimals
          });
        }
      }

      // 匹配转出和转入，找到转账对
      const processed = new Set<string>();
      
      for (const [key1, balance1] of tokenBalanceChanges) {
        if (processed.has(key1) || balance1.change >= 0) continue; // 只处理转出
        
        // 寻找相同mint的转入
        for (const [key2, balance2] of tokenBalanceChanges) {
          if (processed.has(key2) || key1 === key2) continue;
          if (balance1.mint !== balance2.mint || balance2.change <= 0) continue;
          
          // 检查转账金额是否匹配（允许小误差）
          const transferAmount = Math.abs(balance1.change);
          const receiveAmount = balance2.change;
          
          if (Math.abs(transferAmount - receiveAmount) < 0.000001) {
            // 找到匹配的转账对
            const tokenInfo = await this.getSPLTokenInfo(balance1.mint);
            if (!tokenInfo) continue;
            
            const valueUSD = transferAmount * tokenInfo.priceUSD;
            
    
            
            // 检查是否为大额转账
            if (valueUSD < this.getMinTransactionValue()) continue;
            
            // 获取地址标签
            let fromLabel, toLabel;
            if (this.addressLabelService) {
              fromLabel = await this.addressLabelService.getAddressLabel(balance1.owner, ChainType.SOLANA);
              toLabel = await this.addressLabelService.getAddressLabel(balance2.owner, ChainType.SOLANA);
            }

            const transaction: Transaction = {
              id: `sol_token_${tx.transaction.signatures[0]}_${balance1.mint}`,
              hash: tx.transaction.signatures[0] || '',
              chain: ChainType.SOLANA,
              from: balance1.owner || '',
              to: balance2.owner || '',
              value: transferAmount.toString(),
              valueUSD,
              blockNumber: slot,
              timestamp: new Date(blockTime * 1000),
              tokenAddress: balance1.mint,
              tokenSymbol: tokenInfo.symbol,
              tokenDecimals: tokenInfo.decimals,
              fromLabel: fromLabel ? { type: fromLabel.type, label: fromLabel.label } : undefined,
              toLabel: toLabel ? { type: toLabel.type, label: toLabel.label } : undefined,
              confirmed: true
            };

            let logMessage = `💎 ${tokenInfo.symbol}大额转账: $${valueUSD.toLocaleString()} | 数量: ${transferAmount.toLocaleString()} ${tokenInfo.symbol}`;
            
            if (fromLabel) {
              logMessage += `, 发送方: ${fromLabel.label} (${fromLabel.type})`;
            }
            if (toLabel) {
              logMessage += `, 接收方: ${toLabel.label} (${toLabel.type})`;
            }
            logMessage += ` | Slot: ${slot}`;
            
            logger.warn(logMessage);

            if (this.onTransactionCallback) {
              this.onTransactionCallback(transaction);
            }
            
            processed.add(key1);
            processed.add(key2);
            break;
          }
        }
      }

    } catch (error) {
      logger.debug(`处理SPL代币转账失败:`, error);
    }
  }

  // 处理原生SOL转账
  private async processNativeSOLTransfer(tx: SolanaTransaction, slot: number, blockTime: number): Promise<void> {
    try {
      const { preBalances, postBalances } = tx.meta;
      const accountKeys = tx.transaction.message.accountKeys;

      if (!preBalances || !postBalances || !accountKeys) return;

      // 计算余额变化（lamports转SOL，1 SOL = 10^9 lamports）
      let maxTransferSOL = 0;
      let fromAddress = '';
      let toAddress = '';

      const minLength = Math.min(preBalances.length, postBalances.length, accountKeys.length);

      // 分别找出发送方和接收方
      let maxOutflow = 0;  // 最大流出
      let maxInflow = 0;   // 最大流入

      for (let i = 0; i < minLength; i++) {
        const preBalance = preBalances[i];
        const postBalance = postBalances[i];
        const accountKey = accountKeys[i];
        
        if (typeof preBalance !== 'number' || typeof postBalance !== 'number' || !accountKey) {
          continue;
        }
        
        const balanceChange = (postBalance - preBalance) / 1e9; // 转换为SOL
        
        // 记录最大流出（发送方）
        if (balanceChange < 0 && Math.abs(balanceChange) > maxOutflow) {
          maxOutflow = Math.abs(balanceChange);
          fromAddress = accountKey;
        }
        
        // 记录最大流入（接收方）  
        if (balanceChange > 0 && balanceChange > maxInflow) {
          maxInflow = balanceChange;
          toAddress = accountKey;
        }
      }

      // 使用较大的转账金额作为交易金额
      maxTransferSOL = Math.max(maxOutflow, maxInflow);

      // 检查是否为大额交易
      const solPriceUSD = await this.getSOLPrice();
      const valueUSD = maxTransferSOL * solPriceUSD;

      if (valueUSD < this.getMinTransactionValue()) return;

      // 获取地址标签
      let fromLabel, toLabel;
      if (this.addressLabelService && fromAddress && toAddress) {
        fromLabel = await this.addressLabelService.getAddressLabel(fromAddress, ChainType.SOLANA);
        toLabel = await this.addressLabelService.getAddressLabel(toAddress, ChainType.SOLANA);
      }

      const transaction: Transaction = {
        id: `sol_native_${tx.transaction.signatures[0]}`,
        hash: tx.transaction.signatures[0] || '',
        chain: ChainType.SOLANA,
        from: fromAddress,
        to: toAddress,
        value: maxTransferSOL.toString(),
        valueUSD,
        blockNumber: slot,
        timestamp: new Date(blockTime * 1000),
        tokenSymbol: 'SOL',  // 添加代币符号
        fromLabel: fromLabel ? { type: fromLabel.type, label: fromLabel.label } : undefined,
        toLabel: toLabel ? { type: toLabel.type, label: toLabel.label } : undefined,
        confirmed: true
      };

      let logMessage = `💎 SOL大额转账: $${valueUSD.toLocaleString()} | 数量: ${maxTransferSOL.toLocaleString()} SOL`;
      
      if (fromLabel) {
        logMessage += `, 发送方: ${fromLabel.label} (${fromLabel.type})`;
      }
      if (toLabel) {
        logMessage += `, 接收方: ${toLabel.label} (${toLabel.type})`;
      }
      logMessage += ` | Slot: ${slot}`;
      
      logger.warn(logMessage);

      if (this.onTransactionCallback) {
        this.onTransactionCallback(transaction);
      }

    } catch (error) {
      logger.debug(`处理原生SOL转账失败:`, error);
    }
  }

  // 获取SOL价格
  private async getSOLPrice(): Promise<number> {
    return await this.priceService.getTokenPrice('SOL');
  }

  // 获取SPL代币信息
  private async getSPLTokenInfo(mintAddress: string): Promise<{ symbol: string; decimals: number; priceUSD: number } | null> {
    try {
      // 主要的SPL代币映射
      const knownTokens: Record<string, { symbol: string; decimals: number; coingeckoId: string }> = {
        // USDC
        'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v': { symbol: 'USDC', decimals: 6, coingeckoId: 'usd-coin' },
        // USDT
        'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB': { symbol: 'USDT', decimals: 6, coingeckoId: 'tether' },
        // RAY (Raydium)
        '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R': { symbol: 'RAY', decimals: 6, coingeckoId: 'raydium' },
        // SRM (Serum)
        'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt': { symbol: 'SRM', decimals: 6, coingeckoId: 'serum' },
        // BONK
        'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263': { symbol: 'BONK', decimals: 5, coingeckoId: 'bonk' },
        // WIF (dogwifhat)
        'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm': { symbol: 'WIF', decimals: 6, coingeckoId: 'dogwifcoin' },
        // STEP
        'StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT': { symbol: 'STEP', decimals: 9, coingeckoId: 'step-finance' },
      };

      const tokenInfo = knownTokens[mintAddress];
      if (!tokenInfo) {
        logger.debug(`未知的SPL代币: ${mintAddress}`);
        return null;
      }

      // 从PriceService获取价格
      const priceUSD = await this.priceService.getTokenPrice(tokenInfo.coingeckoId);
      
      return {
        symbol: tokenInfo.symbol,
        decimals: tokenInfo.decimals,
        priceUSD
      };

    } catch (error) {
      logger.debug(`获取SPL代币信息失败: ${mintAddress}`, error);
      return null;
    }
  }
} 